﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Threading;
using System.Configuration;

namespace hmi
{    
    class SerialComm:ICommunication
    {
        private SerialPort _port = new SerialPort();//SerialPor执行Close后不会释放资源，所以无需重新 new SerialPort()，可直接重新Open()
        public static int BUFFER_SIZE = 1024;//用在串口数据缓存设置     

        public bool IsPortAvailable{get; set;}

        public bool IsCommRight { get; set; }

        public SerialComm()
        {
            InitPara();
        }

        public SerialPort Port
        {
            get
            {
                return _port;
            }
        } 

        private void InitPara()
        {
            IsCommRight = true;
            IsPortAvailable = false;
            string[] portNames = SerialPort.GetPortNames();//获取可用串口
            if (portNames.Length > 0)//有串口可用
            {
                string portNumStr = ConfigurationManager.AppSettings["PortNum"];
                if (portNumStr == "" || !portNames.Contains(portNumStr))
                {
                    Port.PortName = portNames[0];//没有串口存储值或者当前可选串口中未包含存储值,默认选取可选的第一个串口
                }
                else
                {
                    Port.PortName = portNumStr;
                }
            }
            else//未检测到串口，打开串口时会弹出提示窗口，此处不处理
            {
                return;
            }
            IsPortAvailable = true;
            Port.BaudRate = Convert.ToInt32(ConfigurationManager.AppSettings["BaudRate"]);//波特率
            Port.DataBits = Convert.ToInt32(ConfigurationManager.AppSettings["DataBits"]);//数据位
            Port.StopBits = (StopBits)Convert.ToInt32(ConfigurationManager.AppSettings["StopBits"]);//停止位
            Port.Parity = (Parity)Convert.ToInt32(ConfigurationManager.AppSettings["Parity"]);//校验位默认设置值为偶校验            
            Port.ReceivedBytesThreshold = 1;
            Port.DataReceived += DataReceived;

            Port.ReadTimeout = 8000;//串口读超时8秒
            Port.WriteTimeout = 8000;//串口写超时8秒，在1ms自动发送数据时拔掉串口，写超时5秒后，会自动停止发送，如果无超时设定，这时程序假死
            Port.ReadBufferSize = BUFFER_SIZE;//数据读缓存
            Port.WriteBufferSize = BUFFER_SIZE;//数据写缓存            
        }

        public bool IsOpen
        {
            get
            {
                return Port.IsOpen;
            }
        }

        public void Open()
        {
            Close();
            try
            {
                Port.Open();//如果打开失败，需要相应处理
            }
            catch
            {
                IsCommRight = false;
                return;
            }
            IsCommRight = true;
        }

        public void Close()
        {
            if (Port.IsOpen)
            {
                Port.Close();
            }
        }

        public void SendByteData(byte[] byteData)
        {
            if (!IsOpen)
            {
                return;
            }            
            Port.Write(byteData, 0, byteData.Length);                      
        }

        private void DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(1);
            //byte[] readBuffer = new byte[ComPort.ReadBufferSize];//ComPort.ReadBufferSize 之前设定为BUFFER_SIZE
            byte[] readBuffer = new byte[Port.BytesToRead];
            Port.Read(readBuffer, 0, readBuffer.Length); 
            
            Protocol.Instance.ExtractData(readBuffer);//提取有用的数据
            CommManage.Instance.ReceiveBytesDebug(readBuffer);//收到的原始数据交由调试界面显示
        }
    }
}
